-------------------------------------------------------------------------------
-- Addon - Aggro - Init
-------------------------------------------------------------------------------
-- Version
local MAJOR = "Avion2_Aggro"
local MINOR = tonumber(("@project-revision@"):match("%d+")) or 0

-- Dependencies
if not Avion2Core 				then error(MAJOR .. " requires Avion2.") end
if not LibStub("AceEvent-3.0")	then error(MAJOR .. " requires AceEvent-3.0.") end

-- Create
Avion2_Aggro 		= Avion2Core:NewModule(MAJOR, "AceEvent-3.0")
Avion2_Aggro.major 	= MAJOR
Avion2_Aggro.minor 	= MINOR


-------------------------------------------------------------------------------
-- Addon - Aggro - Variables
-------------------------------------------------------------------------------
-- Translation
local L 		= LibStub("AceLocale-3.0"):GetLocale(MAJOR)
local coreL		= LibStub("AceLocale-3.0"):GetLocale(Avion2Core.major)

-- CombatStatus
Avion2_Aggro.inCombat = false

-- Local functions
local CombatEnter, CombatLeave, UpdateAggro


-------------------------------------------------------------------------------
-- Addon - Aggro - Register with core
-------------------------------------------------------------------------------
-- Register SavedVariables
function Avion2_Aggro:RegisterModuleDB()
	-- Register own saved variables DB
	self.db = Avion2Core.db:RegisterNamespace(Avion2_Aggro.major, {
		profile = {
			combatEnter = { 
				animationList 		= { },
				cancelAnimation		= 0,
			},
			threatSituation = {
				[0] = { 
					animationList 		= { },
					cancelAnimation		= 0,
				},
				[1] = { 
					animationList 		= { },
					cancelAnimation		= 0,
				},
				[2] = { 
					animationList 		= { },
					cancelAnimation		= 0,
				},
				[3] = { 
					animationList 		= { },
					cancelAnimation		= 0,
				},
			},
			tanking = { 
				animationList 		= { },
				cancelAnimation		= 0,
				tankMode			= false,
			},
			lastMinor 		= MINOR,
		},
	})
	
	
	-- Updateto to new rev, data converters should go here
	self.db.profile.lastMinor = Avion2_Aggro.minor
end


-- (Un)register (un)needed events
function Avion2_Aggro:UpdateEventRegistration()
	-- See if there is a threat situation with an animation
	local enabled = false
	for key, value in pairs(self.db.profile.threatSituation) do
		if (#value.animationList > 0) then
			enabled = true
		end
	end
	
	-- Aggro events
	if (self:IsEnabled() and enabled) then
		self:RegisterEvent("UNIT_THREAT_SITUATION_UPDATE", UpdateAggro)
	else
		self:UnregisterEvent("UNIT_THREAT_SITUATION_UPDATE")
	end
	
	-- Cambat enter event
	if (self.db and self.db.profile and self:IsEnabled() and (enabled or #self.db.profile.combatEnter.animationList > 0)) then
		self:RegisterEvent("PLAYER_ENTER_COMBAT", 	CombatEnter)
		self:RegisterEvent("PLAYER_REGEN_DISABLED", CombatEnter)
		self:RegisterEvent("PLAYER_LEAVE_COMBAT", 	CombatLeave)
		self:RegisterEvent("PLAYER_REGEN_ENABLED", 	CombatLeave)
	else
		self:UnregisterEvent("PLAYER_ENTER_COMBAT")
		self:UnregisterEvent("PLAYER_REGEN_DISABLED")
		self:UnregisterEvent("PLAYER_LEAVE_COMBAT")
		self:UnregisterEvent("PLAYER_REGEN_ENABLED")
	end
end


-- Update animation (convert animationFunc: string name to function pointer)
function Avion2_Aggro:LoadAnimationTables()
	if (self.db and self.db.profile) then
		Avion2Core:LoadAnimationTables(self.db.profile.combatEnter.animationList)
		Avion2Core:LoadAnimationTables(self.db.profile.tanking.animationList)
		for key, value in pairs(self.db.profile.threatSituation) do
			Avion2Core:LoadAnimationTables(value.animationList)
		end
	end
end


-------------------------------------------------------------------------------
-- Addon - Aggro - Options
-------------------------------------------------------------------------------
-- Fetch animationTable from animationID (as suplied by eg. Menu_Reuqest)
function Avion2_Aggro:GetAnimationTable(animationID)
	success, _, arg1, arg2, arg3 = self:Deserialize(animationID)
	
	if (success and self.db and self.db.profile) then
		if (arg3 == "combatEnter") then
			return self.db.profile.combatEnter.animationList[arg2]
		elseif (arg3 == "threatSituation") then
			return self.db.profile.threatSituation[arg1].animationList[arg2]
		elseif (arg3 == "tanking") then
			return self.db.profile.tanking.animationList[arg2]
		else
			return false
		end
	else
		return false
	end
end


-- Build Optionstable
function Avion2_Aggro:UpdateOptionTable(args)
	-- Update options when enabled and initialized
	if (self.db and self:IsEnabled()) then
		-- Options for raid member gained aggro
		args[self.major .. "_combatEnter"] = {
			type = 'group',
			name = L["CombatEnter"],
			desc = L["CombatEnter_Desc"],
			args = { 
				new = Avion2Core:GetDefaultNewAnimationOption(self.db.profile.combatEnter.animationList, self),
				cancelAnimation = {
					order = 2,
					type = 'select',
					name = coreL["CancelAnimation"],
					desc = coreL["CancelAnimation_Desc"],
					values = {
						[0] = coreL["DontCancel"],
						[1] = coreL["FadeOut"],
						[2] = coreL["Cancel"],
					},
					get = function()
						return self.db.profile.combatEnter.cancelAnimation
					end,
					set = function(info, val)
						self.db.profile.combatEnter.cancelAnimation = val
					end,
				},
			},
			icon = self:GetIconPath() .. "Combat"
		}
		-- Add options for each animation
		for animationListID, _ in pairs(self.db.profile.combatEnter.animationList) do
			-- Combine all info to find this animation in module db in ONE string
			serializedInfo = self:Serialize(Avion2_Aggro.major, "combatEnter", animationListID, "combatEnter")
			
			-- Update option table
			args[self.major .. "_combatEnter"].args[string.format("Animation_%d", animationListID)] = Avion2Core:GetDefaultAnimationOption(self.db.profile.combatEnter.animationList, animationListID, serializedInfo, self)
		end
		
		-- Options for (not) tanking
		args[self.major .. "_tanking"] = {
			type = 'group',
			name = L["Tanking"],
			desc = L["Tanking_Desc"],
			args = { 
				new = Avion2Core:GetDefaultNewAnimationOption(self.db.profile.tanking.animationList, self),
				tankMode = {
					order = 2,
					type = 'toggle',
					name = L["TankMode"],
					desc = L["TankMode_Desc"],
					get = function()
						return self.db.profile.tanking.tankMode
					end,
					set = function(info, val)
						self.db.profile.tanking.tankMode = val
					end,
				},
				cancelAnimation = {
					order = 3,
					type = 'select',
					name = coreL["CancelAnimation"],
					desc = coreL["CancelAnimation_Desc"],
					values = {
						[0] = coreL["DontCancel"],
						[1] = coreL["FadeOut"],
						[2] = coreL["Cancel"],
					},
					get = function()
						return self.db.profile.tanking.cancelAnimation
					end,
					set = function(info, val)
						self.db.profile.tanking.cancelAnimation = val
					end,
				},
				
			},
			icon = self:GetIconPath() .. "Threat"
		}
		-- Add options for each animation
		for animationListID, _ in pairs(self.db.profile.tanking.animationList) do
			-- Combine all info to find this animation in module db in ONE string
			serializedInfo = self:Serialize(Avion2_Aggro.major, "tanking", animationListID, "tanking")
			
			-- Update option table
			args[self.major .. "_tanking"].args[string.format("Animation_%d", animationListID)] = Avion2Core:GetDefaultAnimationOption(self.db.profile.tanking.animationList, animationListID, serializedInfo, self)
		end

		-- Options for each threat  situation
		for key, value in pairs(self.db.profile.threatSituation) do
			args[string.format(self.major .. "_threatSituation_%d", key)]	= {
				type = 'group',
				name = string.format(L["ThreatSituation"], key),
				desc = L["ThreatSituation_Desc"],
				args = { 
					new = Avion2Core:GetDefaultNewAnimationOption(value.animationList, self),
					cancelAnimation = {
						order = 2,
						type = 'select',
						name = coreL["CancelAnimation"],
						desc = coreL["CancelAnimation_Desc"],
						values = {
							[0] = coreL["DontCancel"],
							[1] = coreL["FadeOut"],
							[2] = coreL["Cancel"],
						},
						get = function()
							return value.cancelAnimation
						end,
						set = function(info, val)
							value.cancelAnimation = val
						end,
					},
				},
				icon = self:GetIconPath() .. "Level" .. tostring(key)
			}
			-- Add options for each animation
			for animationListID, _ in pairs(value.animationList) do
				-- Combine all info to find this animation in module db in ONE string
				serializedInfo = self:Serialize(Avion2_Aggro.major, key, animationListID, "threatSituation")
				
				-- Update option table
				args[string.format(self.major .. "_threatSituation_%d", key)].args[string.format("Animation_%d", animationListID)] = Avion2Core:GetDefaultAnimationOption(value.animationList, animationListID, serializedInfo, self)
			end
		end
	else
		args[self.major .. "_combatEnter"]		= nil
		args[self.major .. "_tanking"]			= nil
		for key, value in pairs(self.db.profile.threatSituation) do
			args[string.format(self.major .. "_threatSituation_%d", key)]	= nil
		end
	end
end


-------------------------------------------------------------------------------
-- Addon - Aggro - Events
-------------------------------------------------------------------------------
-- Player entered combat
CombatEnter = function ()
	Avion2_Aggro.inCombat = true
	Avion2Core:TriggerAnimationList("Avion2_CombatEnter", Avion2_Aggro.db.profile.combatEnter.animationList)
end


-- Player entered combat
CombatLeave = function ()
	Avion2_Aggro.inCombat = false
	if (Avion2_Aggro.db.profile.CombatEnter.cancelAnimation ~= 0) then
		Avion2Core:StopAnimationList("Avion2_CombatEnter", Avion2_Aggro.db.profile.combatEnter.animationList, (Avion2_Aggro.db.profile.combatEnter.cancelAnimation == 1))
	end
	
	-- Update threat when leaving combat
	UpdateAggro("player")
end


-- Unit gained/lost aggro, trigger animation
UpdateAggro = function (unitID)
	-- Only for self
	if (unitID ~= "player") then return end
	
	-- Only enable in combat
	if (Avion2_Aggro.inCombat) then
		-- Get current threat level
		local threatSituation = UnitThreatSituation(unitID)
		
		-- Stop (running)  animations (if set so by profile)
		for key, value in pairs(Avion2_Aggro.db.profile.threatSituation) do
			if (threatSituation == key) then
				if (self.lastThreatSituation ~= threatSituation) then
					Avion2Core:TriggerAnimationList(string.format("Avion2_ThreatSituation_%d", key), value.animationList)
				end
			elseif (value.cancelAnimation ~= 0) then
				Avion2Core:StopAnimationList(string.format("Avion2_ThreatSituation_%d", key), value.animationList, (value.cancelAnimation == 1))
			end
		end
		
		-- (Not) tanking warning
		local isTanking = UnitDetailedThreatSituation(unitID)
		if (
			self.lastIsTanking ~= isTanking and (
			not Avion2_Aggro.db.profile.tanking.tankMode and     isTanking or
				Avion2_Aggro.db.profile.tanking.tankMode and not isTanking 
		)) then
			Avion2Core:TriggerAnimationList("Avion2_Tanking", Avion2_Aggro.db.profile.tanking.animationList)
		end
		
		-- Update last status so we don't trigger twice
		self.lastThreatSituation 	= threatSituation
		self.lastIsTanking 			= isTanking
	else
		-- Stop (running)  animations (if set so by profile)
		for key, value in pairs(Avion2_Aggro.db.profile.threatSituation) do
			if (value.cancelAnimation ~= 0) then
				Avion2Core:StopAnimationList(string.format("Avion2_ThreatSituation_%d", key), value.animationList, (value.cancelAnimation == 1))
			end
		end
		
		-- Stop tanking notifier
		if (Avion2_Aggro.db.profile.tanking.cancelAnimation ~= 0) then
			Avion2Core:StopAnimationList("Avion2_Tanking", Avion2_Aggro.db.profile.tanking.animationList, (Avion2_Aggro.db.profile.tanking.cancelAnimation == 1))
		end
		
		-- Update last status so we don't trigger twice
		self.lastThreatSituation 	= nil
		self.lastIsTanking 			= nil
	end
end
